home *** CD-ROM | disk | FTP | other *** search
- /*
- * GEM calculator
- * resource-dependent part: execution
- * Copyright 1985 Axel T. Schreiner, Ulm, W-Germany
- */
-
- #include "b:\calc\calc.h" /* resource */
-
- /*
- * tunable
- */
-
- #define MAXSTACK 20 /* stack size kludge */
-
- typedef long number; /* computational object */
-
- #define MINLEN 6 /* minimum display length */
- #define FMTd "%c %*ld" /* decimal output */
- #define FMTx "%c 0x%0*lx" /* hexadecimal output */
- #define FMTo "%c 0%0*lo" /* octal output */
-
- /*
- * definitions
- */
-
- #define IDLE 0 /* no number started */
- #define NUMBER 1 /* number started */
-
- typedef struct stack { /* value and operator stack */
- struct stack * next;
- number val; /* must also contain int operator */
- } stack;
-
- /* need fake dynamic stack, since
- GEMLIB does not support malloc */
- static stack elts[MAXSTACK], *avail, *top = elts;
-
- /*
- * calculator utilities
- */
-
- static int pos(op) /* packed operator index */
- register int op;
- { static int list[] =0{
- BLPAR, BOR, BXOR, BAND, BLSH,
- BRSH, BADD, BSUB, BMULT, BDIV,
- BREM
- };
- register int i;
-
- for (i = 0; list[i] != op; ++ i)
- ;
- return i; /* assume we find it... */
- }
-
- static int high(a, b) /* true if a has priority over b */
- register int a, b;
- { static int prio[] = { /* operator priority */
- /* BLPAR */ 1,
- /* BOR */ 2,
- /* BXOR */ 3,
- /* BAND */ 4,
- /* BLSH, BRSH */ 5, 5,
- /* BADD, BSUB */ 6, 6,
- /* BMULT, BDIV, BREM */ 7, 7, 7
- };
-
- return prio[pos(a)] > prio[pos(b)];
- }
-
- static number bin(op, a, b) /* execute binary operator */
- register int op;
- number a, b;
- {
- switch (op) {
- case BOR: return a | b;
- case BXOR: return a ^ b;
- case BAND: return a & b;
- case BLSH: return a << b;
- case BRSH: return a >> b;
- case BADD: return a + b;
- case BSUB: return a - b;
- case BMULT: return a * b;
- case BDIV: return b? a / b: 0;
- case BREM: return b? a % b: 0;
- }
- }
-
- static stack * push(next, val)
- register stack * next; /* onto this stack */
- number val; /* this value */
- { register stack * p;
-
- if (avail) /* recycle */
- p = avail, avail = avail->next;
- else if (top) /* use new element */
- { p = top;
- if (++ top >= elts + MAXSTACK)
- top = (stack *) 0;
- }
- else /* sorry, Charlie... */
- { Alert(ASTACK);
- return (stack *) 0;
- }
- p->next = next;
- p->val = val;
- return p;
- }
-
- static free(p)
- stack * p;
- {
- p->next = avail, avail = p;
- }
-
- /*
- * calculator
- */
-
- int Calc(code, bp, l) /* true if we should quit */
- register int code; /* digit or operation */
- char * bp; /* first call: output buffer */
- int l; /* first call: text length */
- { static stack * opr, /* operator stack */
- * ond; /* operand stack */
- static int state = IDLE, /* of automaton */
- sign = 1, /* extra sign of display */
- base = 10, /* base for display */
- lpar = 0; /* open ( */
- static number display = 0, /* assembled number */
- value = 0; /* sign included */
- static char * buf; /* display buffer */
- static int len;
-
- register stack * p;
-
- if (! buf) /* first call */
- if ((len = l) < MINLEN)
- { Alert(ASMALL);
- return 1;
- }
- else
- buf = bp;
-
- switch (code) {
- case BZERO: code = 0; goto digit;
- case BONE: code = 1; goto digit;
- case BTWO: code = 2; goto digit;
- case BTHREE: code = 3; goto digit;
- case BFOUR: code = 4; goto digit;
- case BFIVE: code = 5; goto digit;
- case BSIX: code = 6; goto digit;
- case BSEVEN: code = 7; goto digit;
- case BEIGHT: code = 8; goto digit;
- case BNINE: code = 9; goto digit;
- case BA: code = 10; goto digit;
- case BB: code = 11; goto digit;
- case BC: code = 12; goto digit;
- case BD: code = 13; goto digit;
- case BE: code = 14; goto digit;
- case BF: code = 15;
- digit:
- if (state == IDLE)
- display = 0, state = NUMBER;
- display = display * base + code;
- value = sign*display;
- break;
- case BMINUS:
- sign = - sign;
- value = sign*display;
- break;
- case BCOMP: /* hmmmm... */
- display = ~display;
- value = sign*display;
- break;
- case BDEC:
- base = 10;
- break;
- case BOCT:
- base = 8;
- break;
- case BHEX:
- base = 16;
- break;
- case BEQUAL:
- while (opr)
- { if (opr->val != BLPAR)
- { value = bin((int) opr->val, ond->val, value);
- p = ond->next, free(ond), ond = p;
- }
- p = opr->next, free(opr), opr = p;
- }
- display = value, sign = 1, state = IDLE;
- break;
- case BOR:
- case BXOR:
- case BAND:
- case BLSH:
- case BRSH:
- case BADD:
- case BSUB:
- case BMULT:
- case BDIV:
- case BREM:
- while (opr && ! high(code, (int) opr->val))
- { value = bin((int) opr->val, ond->val, value);
- p = ond->next, free(ond), ond = p;
- p = opr->next, free(opr), opr = p;
- }
- if (! (p = push(opr, (number) code)))
- goto clear;
- opr = p;
- if (! (p = push(ond, value)))
- goto clear;
- ond = p;
- display = value, sign = 1, state = IDLE;
- break;
- case BLPAR:
- if (state == IDLE)
- { ++ lpar;
- if (! (p= push(opr, (number) code)))
- goto clear;
- opr = p;
- }
- else
- Alert(APAREN);
- return 0;
- case BRPAR:
- if (state == IDLE || ! lpar)
- { Alert(APAREN);
- return 0;
- }
- while (opr && opr->val != BLPAR)
- { value = bin((int) opr->val, ond->val, value);
- p = ond->next, free(ond), ond = p;
- p = opr->next, free(opr), opr = p;
- }
- --lpar, p = opr->next, free(opr), opr = p;
- display = value, sign = 1, state = IDLE;
- break;
- case BCLEAR:
- clear:
- while (opr)
- p = opr->next, free(opr), opr = p;
- while (ond)
- p = ond->next, free(ond), ond = p;
- lpar = 0;
- base = 10;
- case BCENTRY:
- display = value = 0;
- sign = 1;
- state = IDLE;
- }
- sprintf(buf,
- base == 8? FMTo: base == 16? FMTx: FMTd,
- value < 0? '-': ' ',
- base == 8? len-4: base == 16? len-5: len-3,
- value < 0? -value: value);
- return 0;
- }
- ə